// +build ignore

#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>

#include <linux/stddef.h>
#include <linux/pkt_cls.h>
#include <linux/if_ether.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/ipv6.h>

#include <bpf/bpf_helpers.h>
#include <bpf/bpf_endian.h>

#include "shared_map_des.h"

char __license[] SEC("license") = "GPL";

#ifndef ctx_ptr
# define ctx_ptr(field)		(void *)(long)(field)
#endif

#define errindex  -1

static __always_inline struct backend_des* is_remote_ep_v4(struct __sk_buff *skb)
{
	void *data_end = ctx_ptr(skb->data_end);
	void *data = ctx_ptr(skb->data);
	struct iphdr *ip4h;

	if (data + sizeof(struct ethhdr) > data_end)
		return NULL;

	ip4h = (struct iphdr *)(data + sizeof(struct ethhdr));
	if ((void *)(ip4h + 1) > data_end)
		return NULL;

    __u32 original_dest_ip = ip4h->daddr;
    struct backend_des *bk;
	bk = bpf_map_lookup_elem(&SIGNAL_MAP, &original_dest_ip);
	if (!bk) {
		bpf_printk("no backends for ip %x", original_dest_ip);
		return NULL;
	}
	return bk;
}

SEC("classifier/from-container-des")
int from_container_des(struct __sk_buff *skb)
{
	__u8 zero[ETH_ALEN * 2];
	struct backend_des *bk = NULL;
	switch (skb->protocol) {
	case __bpf_constant_htons(ETH_P_IP):
		bk = is_remote_ep_v4(skb);
		break;
	}
	if (!bk)
		return TC_ACT_OK;
	__builtin_memset(&zero, 0, sizeof(zero));
	if (bpf_skb_store_bytes(skb, 0, &zero, sizeof(zero), 0) < 0)
		return TC_ACT_SHOT;
	return bpf_redirect_neigh(bk->ifdindex, NULL, 0, 0);
}